﻿#region Librerias

using System;
using System.ComponentModel;
using System.IO;
using System.Security.Permissions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using ESF.General;
using System.Collections.Generic;
using AjaxControlToolkit;
using System.Drawing;
using System.Text;

#endregion


namespace ESF.Web.ServerControls
{
	[AspNetHostingPermission(SecurityAction.Demand,
        Level = AspNetHostingPermissionLevel.Minimal),
    AspNetHostingPermission(SecurityAction.InheritanceDemand, 
        Level = AspNetHostingPermissionLevel.Minimal),
	ToolboxData("<{0}:ExtendedFileUploader runat=\"server\"></{0}:ExtendedFileUploader>")]
	public class ExtendedFileUploader : WebControl, INamingContainer
	{
		#region Miembros

		private HyperLink lnkFileHyperLink;
		private AsyncFileUpload filUploader;

		private Button btnDelete;
		private Label lblTitle;
		private Label lblInstructions;
		private DropDownList ddlDirectoryList;
		private CheckBox chkUseSameFileNameFromOriginal;
		private GenericTreeView trvServerFolder;
		private CheckBox chkUseExistentFile;
		
		#endregion


		#region Propiedades

		public string SessionFilepath
		{
			get
			{
				return HttpContext.Current.Session [GetFilenamesessionName()] as string;
			}
			set
			{
				HttpContext.Current.Session [GetFilenamesessionName()] = value;
			}
		}


		public string UniqueIdentifier
		{
			get
			{
				if (ViewState ["UniqueIdentifier"] == null)
				{
					ViewState ["UniqueIdentifier"] = Guid.NewGuid ().ToString ();
				}

				return ViewState ["UniqueIdentifier"] as string;
			}
		}
		

		[Bindable(true)]
		[Category("Presentation")]
		[DefaultValue("Archivo")]
		[Localizable(true)]
		public string Title
		{
			set
			{
				EnsureChildControls ();
				
				lblTitle.Text = value;
			}
		}


		public bool AllowDelete 
		{
			set
			{
				EnsureChildControls ();

				btnDelete.Visible = value;
			}
		}


		public bool EnableUseExistentFile
		{
			set
			{
				ViewState ["EnableUseExistentFile"] = value;
			}
			get
			{
				if (ViewState ["EnableUseExistentFile"] == null) { return true; }

				return (bool) ViewState ["EnableUseExistentFile"];
			}
		}

		
		public string PublishFolderAppSettingKey
		{
			set
			{
				EnsureChildControls ();

				PublishFolderRelativePath = ReadConfig.GetAppSetting (value + ".RelativeFolderFile", string.Empty);
				
				PublishFolder = ReadConfig.GetAppSetting (value);
				

				ViewState ["PublishFolderAppSettingKey"] = value;
			}
			get
			{
				return ViewState ["PublishFolderAppSettingKey"] as string;
			}
		}


		public string ExtraFolder
		{
			set
			{
				ViewState ["ExtraFolder"] = value;

				ddlDirectoryList.Attributes ["style"] = "display:none;";
			}
			get
			{
				if (ViewState ["ExtraFolder"] == null)
				{
					return string.Empty;
				}
				
				return ViewState ["ExtraFolder"] as string;
			}
		}


		public string PublishVirtualFolder
		{
			set
			{
				PublishFolder = HttpContext.Current.Server.MapPath (value);
			}
		}


		public string PublishFolder
		{
			set
			{
				EnsureChildControls ();

				trvServerFolder.PublishFolder = value;

				trvServerFolder.Browse ();

				ddlDirectoryList.Items.Clear ();


				if (!string.IsNullOrEmpty (value))
				{
					value = FileHelper.AddFinalSeparator (value);

					try
					{
						foreach (string directoryPath in FileHelper.ListDirectories (value))
						{
							// Es el directorio raiz
							if (directoryPath == value)
							{
								ddlDirectoryList.Items.Add (
									new ListItem (
										"Directorio Raiz", 
										directoryPath));
							}
							else
							{
								ddlDirectoryList.Items.Add (
									new ListItem (
										directoryPath.Replace (value, string.Empty), 
										directoryPath));
							}
						}

						if (ddlDirectoryList.Items.Count > 1)
						{
							ddlDirectoryList.Attributes ["style"] = string.Empty;
						}
					}
					catch (Exception pEx)
					{
						throw new GenericException (GenericException.CRI_FOLDER_ERROR, string.Format ("The folder list for {0} can not be loaded", value), pEx);
					}
				}
			}
		}


		public string PublishFolderRelativePath
		{
			set
			{
				EnsureChildControls ();

				ViewState ["PublishFolderRelativePath"] = value;

				trvServerFolder.PublishFolderRelativePath = value;

				PublishFolder = HttpContext.Current.Server.MapPath (value);
			}
			get
			{
				return ViewState ["PublishFolderRelativePath"] as string;
			}
		}


		// Separado por comas
		public string AllowedExtensions
		{
			set
			{
				ViewState ["AllowedExtensions"] = value;
			}
			get
			{
				return ViewState ["AllowedExtensions"] as string;
			}
		}


		public string FilePath
		{
			get
			{
				SavePostedFile ();

				return SessionFilepath;
			}
			set
			{
				EnsureChildControls ();

				SessionFilepath = value;
			}			
		}

		#endregion


		#region Inicializacion

		protected override void CreateChildControls()
		{
			lblTitle = new Label ();
			lblTitle.ID = "lblTitle";
			lblTitle.CssClass = "label";

			lblInstructions = new Label ();
			lblInstructions.CssClass = "instructions";
			lblInstructions.ID = "lblInstructions";
			lblInstructions.Text = TextHelper.ConcatSepIfValueNotEmpty ("Tipos de archivo: ", AllowedExtensions, ",");

			lnkFileHyperLink = new HyperLink ();
			lnkFileHyperLink.CssClass = "instructions";
			lnkFileHyperLink.Target = "_blank";

			filUploader = new AsyncFileUpload ();
			filUploader.CssClass = "fileUploader";
			
			if (HttpContext.Current.Request.Browser.Browser.ToUpper () == "FIREFOX")
			{
				filUploader.Width = new Unit (80, UnitType.Pixel);
			}

			filUploader.CompleteBackColor = Color.LightGreen;
			filUploader.UploadedComplete += new EventHandler<AsyncFileUploadEventArgs>(filUploader_UploadedComplete);
			filUploader.UploadedFileError += new EventHandler<AsyncFileUploadEventArgs>(filUploader_UploadedFileError);
			
			lblTitle.ToolTip = filUploader.ToolTip = string.Format ("Puede publicar un archivo de hasta {0}", TextHelper.ToStringBytes (PageHelper.MaxRequestLengthBytes));

			btnDelete = new Button ();
			btnDelete.ID = "btnDelete";
			btnDelete.Text = "Borrar";
			btnDelete.UseSubmitBehavior = false;
			btnDelete.Attributes ["style"] = "width:80px;margin-right:0px;";
			btnDelete.Visible = false;
			btnDelete.OnClientClick = "$ ('#" + filUploader.ClientID + "_ctl02').val(''); ";
			btnDelete.Click += new EventHandler(btnDelete_Click);

			ddlDirectoryList = new DropDownList ();
			ddlDirectoryList.CssClass = "directoryList";
			ddlDirectoryList.Attributes ["style"] = "display:none;";

			chkUseSameFileNameFromOriginal = new CheckBox ();
			chkUseSameFileNameFromOriginal.Text = "Utilizar nombre original";
			chkUseSameFileNameFromOriginal.CssClass = "chkUseSameFileNameFromOriginal";
			chkUseSameFileNameFromOriginal.ToolTip = "Al marcar este campo se usa el nombre original del archivo en su computador. Siempre se sobreescribe el archivo en el servidor";

			trvServerFolder = new GenericTreeView ();
			trvServerFolder.CssClass = "treeView";
			trvServerFolder.SelectNodeGetChildren += trvServerFolder_SelectNodeGetChildren;
			trvServerFolder.Visible = false;			

			chkUseExistentFile = new CheckBox ();
			chkUseExistentFile.Text = "Utilizar Archivo existente";
			chkUseExistentFile.ID = "chkUseExistentFile";
			chkUseExistentFile.CssClass = "chkUseExistentFile";
			chkUseExistentFile.AutoPostBack = true;
			chkUseExistentFile.CheckedChanged += new EventHandler(chkUseExistentFile_CheckedChanged);

			
			Controls.Add (lblTitle);
			Controls.Add (lblInstructions);
			Controls.Add (lnkFileHyperLink);
			Controls.Add (filUploader);
			Controls.Add (btnDelete);
			Controls.Add (chkUseSameFileNameFromOriginal);
			Controls.Add (ddlDirectoryList);
			Controls.Add (trvServerFolder);
			Controls.Add (chkUseExistentFile);
		}


		protected void filUploader_UploadedFileError(object sender, AsyncFileUploadEventArgs e)
		{
			Log.Error (string.Format ("Uploading failed: The file {0} with size {1} has status {3} ({2})", e.FileName, e.FileSize, e.State,e.StatusMessage));
		}


		protected void filUploader_UploadedComplete(object sender, AsyncFileUploadEventArgs e)
		{
			SavePostedFile ();
		}


		protected object [] trvServerFolder_SelectNodeGetChildren (Dictionary<string,string> pValueList, bool pFromExpand, int pDepth)
		{
			// Es un archivo se selecciona
 			if (!bool.Parse (pValueList ["Extra_II"]))
			{
				FilePath = pValueList ["Code"];

				return null;
			}

			return trvServerFolder.treeView_SelectNodeGetChildren (pValueList, pFromExpand, pDepth);
		}


		protected void chkUseExistentFile_CheckedChanged(object sender, EventArgs e)
		{
			if (chkUseExistentFile.Checked)
			{
				filUploader.Visible = false;
				btnDelete.Visible = false;
				ddlDirectoryList.Visible = false;
				chkUseSameFileNameFromOriginal.Visible = false;
				trvServerFolder.Visible = true;
			}
			else
			{
				filUploader.Visible = true;
				btnDelete.Visible = true;
				ddlDirectoryList.Visible = (ddlDirectoryList.Items.Count > 1);
				chkUseSameFileNameFromOriginal.Visible = true;
				trvServerFolder.Visible = false;
			}
		}


		protected void btnDelete_Click(object sender, EventArgs e)
		{
			try
			{
				if (File.Exists (FilePath))
				{	
					File.Delete (FilePath);
				}

				FilePath = string.Empty;
			}
			catch (Exception pEx)
			{
				JS.LogError (this.Page, pEx);
			}
		}

		#endregion


		#region Funciones

		public void Clear ()
		{
			FilePath = string.Empty;
		}


		public void SavePostedFile ()
		{
			try
			{
				string fileName;
				string currentFilePath;


				if (!filUploader.HasFile) { return; }
				
				currentFilePath = SessionFilepath;

							
				fileName = Path.Combine (ddlDirectoryList.SelectedValue, ExtraFolder);
				
				if (string.IsNullOrEmpty (fileName))
				{
					fileName = Page.MapPath (HttpContext.Current.Request.ApplicationPath) + Path.DirectorySeparatorChar;
				}

				FileHelper.EnsureFolder(fileName);


				if (!string.IsNullOrEmpty (currentFilePath))
				{
					// Borra el archivo con valor anterior vinculado
					if (File.Exists (currentFilePath)) { File.Delete (currentFilePath); }
				}

				if (chkUseSameFileNameFromOriginal.Checked)
				{
					fileName = Path.Combine (fileName, Path.GetFileName (filUploader.FileName));
				}
				else
				{
					if (string.IsNullOrEmpty (currentFilePath))
					{
						fileName = Path.Combine (fileName, Guid.NewGuid ().ToString () + Path.GetExtension (filUploader.FileName));
					}
					else
					{
						fileName = Path.Combine (fileName, Path.GetFileName (currentFilePath));
					}
				}

				// Borra el archivo nuevo a vincular si existe previamente
				if (File.Exists (fileName)) { File.Delete (fileName); }

				filUploader.SaveAs (fileName);
				FilePath = fileName;
			}
			catch (Exception pEx)
			{
				JS.LogError (Page, pEx);
			}
		}

		#endregion


		#region Render

		private string GetFilenamesessionName ()
		{
			return string.Format ("{0}_Filename", UniqueIdentifier);
		}


		protected override void OnPreRender(EventArgs e)
		{
			base.OnPreRender(e);


			StringBuilder js;


			filUploader.OnClientUploadStarted = ClientID + "_VerifyUpload";
			filUploader.OnClientUploadComplete = ClientID + "_UploadComplete";
			filUploader.OnClientUploadError = ClientID + "_UploadError";
			
			
			js = new StringBuilder ();

			js.Append (ClientID + "_VerifyUpload = function (sender, args) { ");
			js.Append ("var filename = args.get_fileName(); ");
			js.Append ("var filext = filename.substring(filename.lastIndexOf('.') + 1).toUpperCase(); return ");
			
			if (string.IsNullOrWhiteSpace (AllowedExtensions))
			{
				js.Append ("true");
			}
			else
			{			
				js.Append (TextHelper.ConcatPartsAvoidEmptyParts (" filext == '", "' || ", AllowedExtensions.Split (',')));
				js.Append (" false");
			}

			js.AppendLine ("; }; ");


			js.AppendLine(ClientID + "_UploadComplete = function (sender, args) { EnableByID ('" + ClientID + "_btnFakeDelete'); $('#" + ClientID + "_lblLocalMsg').html ('El Archivo ha sido publicado!'); HideLoadingMessage (); }");
			
			js.Append (ClientID + "_UploadError = function (sender, args) { ");
			js.AppendLine (" alert (args.get_errorMessage ()); HideLoadingMessage (); } ");
			
			JS.AddEndJS (Page, js.ToString ());

			#region Actualizar Controles 
			
			FileInfo fileInfo;


			if (!string.IsNullOrEmpty(SessionFilepath))
			{
				fileInfo = new FileInfo(SessionFilepath);

				if (fileInfo.Exists)
				{
					lnkFileHyperLink.Text = string.Format("Enlace al Archivo Publicado (Tamaño {0})", TextHelper.ToStringBytes(fileInfo.Length));
					lnkFileHyperLink.NavigateUrl = PageHelper.GetVirtualPath(fileInfo.FullName, PublishFolderRelativePath, true);

					btnDelete.Visible = true;
				}
				else
				{
					lnkFileHyperLink.Text = "El archivo referenciado no existe pero sigue vinculado";
					lnkFileHyperLink.ToolTip = fileInfo.FullName;

					btnDelete.Visible = true;
				}
			}
			else
			{
				lnkFileHyperLink.Text = "No hay archivo publicado";

				btnDelete.Visible = false;
			}

			#endregion
		}


		protected override void OnInit(EventArgs e)
		{
			base.OnInit(e);
		}


		protected override void Render (HtmlTextWriter pWriter)
		{
				pWriter.AddAttribute (HtmlTextWriterAttribute.Class, "divField divFieldUpload");
			pWriter.RenderBeginTag (HtmlTextWriterTag.Div);
	
					lblTitle.RenderControl (pWriter);

					pWriter.AddAttribute (HtmlTextWriterAttribute.Class, "field");
				pWriter.RenderBeginTag (HtmlTextWriterTag.Div);

					filUploader.RenderControl (pWriter);

					btnDelete.RenderControl(pWriter);

					if (!btnDelete.Visible) 
					{
							pWriter.AddAttribute (HtmlTextWriterAttribute.Type, "button");
							pWriter.AddAttribute (HtmlTextWriterAttribute.Value, "Borrar");
							pWriter.AddAttribute (HtmlTextWriterAttribute.Id, ClientID + "_btnFakeDelete");
							pWriter.AddAttribute (HtmlTextWriterAttribute.Disabled, "disabled");
							pWriter.AddAttribute (HtmlTextWriterAttribute.Style, "width:80px;margin-right:0px;");
							pWriter.AddAttribute(HtmlTextWriterAttribute.Onclick, "$ ('#" + filUploader.ClientID + "_ctl02').val (''); " + Page.ClientScript.GetPostBackEventReference(btnDelete, string.Empty));
						pWriter.RenderBeginTag (HtmlTextWriterTag.Input);
						pWriter.RenderEndTag ();
					}
					
					lblInstructions.RenderControl (pWriter);
					chkUseSameFileNameFromOriginal.RenderControl (pWriter);
					

					if (btnDelete.Visible)
					{
						lnkFileHyperLink.RenderControl(pWriter);
					}
					else
					{
							pWriter.AddAttribute (HtmlTextWriterAttribute.Id, ClientID + "_lblLocalMsg");
							pWriter.AddAttribute (HtmlTextWriterAttribute.Class, "instructions");
							
						pWriter.RenderBeginTag (HtmlTextWriterTag.Div);
							pWriter.Write ("No hay archivo publicado");
						pWriter.RenderEndTag ();
					}

					ddlDirectoryList.RenderControl (pWriter);

				pWriter.RenderEndTag ();

				trvServerFolder.RenderControl (pWriter);

				if (EnableUseExistentFile)
				{
					chkUseExistentFile.RenderControl (pWriter);
				}

			pWriter.RenderEndTag ();			
		}

		#endregion
	}
}